package com.luihui.manager;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.lang.reflect.Field;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author:Luhui
 * @qq:729913162
 * @Date:2018/11/3 0003
 * @Time:20:21
 */
public class ConfigProcessor implements BeanPostProcessor,EnvironmentAware {

    private final Map<String,ConfigBean> fieldMap = new ConcurrentHashMap<>();
    private Environment environment;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        for (Field field : bean.getClass().getDeclaredFields()) {
            if(field.isAnnotationPresent(Value.class)){
                String key = field.getAnnotation(Value.class).value();
                if(key.startsWith("${")&&key.endsWith("}")){
                    key = key.substring(2,key.length()-1);
                    fieldMap.put(key,new ConfigBean(field,bean));
                    field.setAccessible(true);
                }
            }
        }
        return bean;
    }


    public void resetConfig(String key) throws IllegalAccessException {
        ConfigBean configBean = fieldMap.get(key);
        String value = environment.getProperty(key);
        Field field = configBean.getField();
        Object fieldValue = field.get(configBean.getObject());
        if(fieldValue instanceof String){
           if(!fieldValue.equals(value)){
               field.set(configBean.getObject(),environment.getProperty(key));
           }
        }else {
            if(fieldValue!=value){
                field.set(configBean.getObject(),environment.getProperty(key));
            }
        }
    }

    @Override
    public void setEnvironment(Environment environment) {
        this.environment=environment;
    }

    private static class ConfigBean{
        private Field field;
        private Object object;

        public Field getField() {
            return field;
        }

        public void setField(Field field) {
            this.field = field;
        }

        public Object getObject() {
            return object;
        }

        public void setObject(Object object) {
            this.object = object;
        }

        public ConfigBean(){}

        public ConfigBean(Field field, Object object) {
            this.field = field;
            this.object = object;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            ConfigBean that = (ConfigBean) o;
            return Objects.equals(field, that.field) &&
                    Objects.equals(object, that.object);
        }

        @Override
        public int hashCode() {
            return Objects.hash(field, object);
        }
    }
}
